package cn.csc.module.shop.service.detail;

import cn.csc.framework.common.exception.ServiceException;
import cn.csc.framework.common.pojo.PageResult;
import cn.csc.framework.mybatis.core.util.MyBatisUtils;
import cn.csc.framework.security.core.util.SecurityFrameworkUtils;
import cn.csc.module.member.api.user.MemberUserApi;
import cn.csc.module.member.api.user.dto.MemberUserRespDTO;
import cn.csc.module.member.api.user.dto.UpdateUserTypeReqDTO;
import cn.csc.module.order.api.order.OrderApi;
import cn.csc.module.product.api.spu.SpuApi;
import cn.csc.module.shop.api.detail.dto.ShopDetailRelateReqDTO;
import cn.csc.module.shop.api.detail.dto.UpdateShopTypeReqDTO;
import cn.csc.module.shop.controller.admin.detail.vo.*;
import cn.csc.module.shop.controller.app.detail.vo.AppShopDetailCreateReqVO;
import cn.csc.module.shop.controller.app.detail.vo.AppShopDetailRespVO;
import cn.csc.module.shop.controller.app.detail.vo.AppShopDetailUpdateShopLogoReqVO;
import cn.csc.module.shop.convert.detail.ShopDetailConvert;
import cn.csc.module.shop.dal.dataobject.detail.ShopDetailDO;
import cn.csc.module.shop.dal.dataobject.user.ShopUserDO;
import cn.csc.module.shop.dal.mysql.detail.ShopDetailMapper;
import cn.csc.module.shop.dal.mysql.user.ShopUserMapper;
import cn.csc.module.shop.enums.ShopTypeEnum;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import static cn.csc.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.csc.module.shop.enums.ErrorCodeConstants.*;

/**
 * 店铺详情 Service 实现类
 *
 * @author liuchuang
 */
@Service
@Validated
@Slf4j
public class ShopDetailServiceImpl extends ServiceImpl<ShopDetailMapper, ShopDetailDO> implements ShopDetailService {

    @Resource
    private ShopUserMapper shopUserMapper;

    @Resource
    private OrderApi orderApi;

    @Resource
    private SpuApi spuApi;

    @Resource
    private MemberUserApi memberUserApi;

    @Override
    public BigInteger createDetail(ShopDetailCreateReqVO createReqVO) {
        // 插入
        ShopDetailDO detail = ShopDetailConvert.INSTANCE.convert(createReqVO);
        baseMapper.insert(detail);
        // 返回
        return detail.getId();
    }

    /**
     * 创建店铺和对应的店铺用户
     * @param reqVO
     * @return
     */
    @Override
    public BigInteger createDetailAndShopUser(AppShopDetailCreateReqVO reqVO) {
        log.info("createDetailAndShopUser reqVO: {}",reqVO);
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        // 重新提交审核
        if (reqVO.getReapply()){
            ShopDetailDO detail = ShopDetailConvert.INSTANCE.convert(reqVO);
            ShopDetailDO shopDetailDO = baseMapper.selectDetailByUserId(BigInteger.valueOf(userId));
            detail.setId(shopDetailDO.getId());
            detail.setType(shopDetailDO.getType());
            // 等待审核
            detail.setAuditStatus(1);
            detail.setUpdateTime(LocalDateTime.now());
            baseMapper.updateById(detail);
            return detail.getId();
        }
        ShopUserDO exist = shopUserMapper.selectByUserId(BigInteger.valueOf(userId));
        if (exist != null){
            throw new ServiceException(SHOP_USER_HAS_BIND);
        }
        // 插入
        ShopDetailDO detail = ShopDetailConvert.INSTANCE.convert(reqVO);
        // 初始都为普通店
        detail.setType(ShopTypeEnum.COMMON.value());
        detail.setShopStatus((byte) 1);
        // 等待审核
        detail.setAuditStatus(1);
        // 审核通过后再更改type
        baseMapper.insert(detail);
        MemberUserRespDTO userRespDTO = memberUserApi.getUser(userId).getCheckedData();
        // 保存当前登录用户与关联店铺的关系
        ShopUserDO shopUserDO = ShopUserDO.builder().shopId(detail.getId())
                .userId(BigInteger.valueOf(userId))
                .phoneNumber(userRespDTO.getMobile()).nickName(userRespDTO.getNickname()).isAdmin((byte) 1)
                .build();
        shopUserMapper.insert(shopUserDO);

        // 返回
        return detail.getId();
    }

    @Override
    public Boolean idCardNoValid(String idCardNo){
        ShopDetailDO detailDO = baseMapper.selectByIdCardNo(idCardNo);
        return detailDO == null;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean relateShopDetail(ShopDetailRelateReqDTO relateReqDTO) {
        ShopDetailDO detail = ShopDetailConvert.INSTANCE.convert(relateReqDTO);
        Optional.ofNullable(relateReqDTO.getId()).ifPresent(id -> detail.setId(id));
        detail.setType(3);
        detail.setAuditStatus(0);
        int insert;
        try {
            insert = baseMapper.insert(detail);
        } catch (DuplicateKeyException e){
            e.printStackTrace();
            throw new ServiceException(COMPANY_HAS_BINDED);
        }
        assert SecurityFrameworkUtils.getLoginUserId() != null;
        // 保存当前登录用户与关联店铺的关系
        ShopUserDO shopUserDO = ShopUserDO.builder().shopId(detail.getId())
                .userId(BigInteger.valueOf(SecurityFrameworkUtils.getLoginUserId()))
                .phoneNumber(relateReqDTO.getPhoneNumber()).nickName(relateReqDTO.getNickName()).isAdmin((byte) 1)
                .build();
        shopUserMapper.insert(shopUserDO);
        return insert > 0 ? Boolean.TRUE : Boolean.FALSE;
    }

    @Override
    public Boolean updateShopType(UpdateShopTypeReqDTO reqDTO){
        ShopDetailDO shopDetailDO = baseMapper.selectDetailByUserId(reqDTO.getUserId());
        if (shopDetailDO.getType() + reqDTO.getType() == 15){
            shopDetailDO.setType(15);
        }else {
            shopDetailDO.setType(reqDTO.getType());
        }
        memberUserApi.updateUserType(new UpdateUserTypeReqDTO(reqDTO.getUserId(), shopDetailDO.getType()));
        baseMapper.updateById(shopDetailDO);
        return true;
    }

    @Override
    public void updateDetail(ShopDetailUpdateReqVO updateReqVO) {
        // 校验存在
        validateDetailExists(updateReqVO.getId());
        // 更新
        ShopDetailDO updateObj = ShopDetailConvert.INSTANCE.convert(updateReqVO);
        baseMapper.updateById(updateObj);
    }

    @Override
    public Integer updateShopLogo(AppShopDetailUpdateShopLogoReqVO reqVO) {
        // 更新
        return baseMapper.updateShopLogo(reqVO);
    }


    @Override
    public void deleteDetail(BigInteger id) {
        // 校验存在
        validateDetailExists(id);
        // 删除
        baseMapper.deleteById(id);
    }

    private void validateDetailExists(BigInteger id) {
        if (baseMapper.selectById(id) == null) {
            throw exception(SHOP_DETAIL_NOT_EXISTS);
        }
    }

    @Override
    public ShopDetailDO getDetail(BigInteger id) {
        return baseMapper.selectById(id);
    }

    /**
     * 通过店铺编号列表获得店铺详情
     *
     * @param shopIds 店铺编号列表
     * @return 店铺详情list
     */
    public List<ShopDetailDO> getShopDetailList(List<BigInteger> shopIds){
        return baseMapper.selectShopDetailList(shopIds);
    }


    @Override
    public ShopDetailDO getSimpleDetail(BigInteger id) {
        return baseMapper.selectSimpleDetailById(id);
    }

    /**
     * 通过用户Id获得店铺详情
     *
     * @param userId 用户编号
     * @return 店铺详情
     */
    @Override
    public ShopDetailDO getDetailByUserId(BigInteger userId) {
        return baseMapper.selectDetailByUserId(userId);
    }

    @Override
    public List<ShopDetailDO> getDetailList(Collection<BigInteger> ids) {
        return baseMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<ShopDetailDO> getDetailPage(ShopDetailPageReqVO pageReqVO) {
        return baseMapper.selectPage(pageReqVO);
    }

    @Override
    public PageResult<ShopDetailWithAuditTimeRespVO> getPageWithAuditTime(ShopDetailPageReqVO pageReqVO) {
        IPage<ShopDetailWithAuditTimeRespVO> mpPage = MyBatisUtils.buildPage(pageReqVO);
        baseMapper.selectPageWithAuditTime(pageReqVO,mpPage);
        long totalPage ;
        if (mpPage.getTotal() > 0) {
            if (mpPage.getTotal() % pageReqVO.getPageSize() <= 0)
                totalPage = mpPage.getTotal() / pageReqVO.getPageSize();
            else
                totalPage = (mpPage.getTotal() / pageReqVO.getPageSize()) + 1;
        } else {
            return new PageResult<>();
        }
        return new PageResult<>(mpPage.getRecords(), mpPage.getTotal(), totalPage);
    }

    @Override
    public PageResult<AppShopDetailRespVO> getSimpleDetailPage(ShopDetailPageReqVO pageReqVO) {
        IPage<AppShopDetailRespVO> mpPage = MyBatisUtils.buildPage(pageReqVO);
        baseMapper.selectSimpleDetailPage(pageReqVO,mpPage);
        long totalPage = 0l;
        if (mpPage.getTotal() > 0) {
            if (mpPage.getTotal() % pageReqVO.getPageSize() <= 0)
                totalPage = mpPage.getTotal() / pageReqVO.getPageSize();
            else
                totalPage = (mpPage.getTotal() / pageReqVO.getPageSize()) + 1;
        } else {
            return new PageResult<>();
        }
        // TODO 查询上架商品数和订单数
        List<BigInteger> shopIds = mpPage.getRecords().stream().map(AppShopDetailRespVO::getId).collect(Collectors.toList());
        Map<String, Object> orderInfo = orderApi.getCountByShopIds(shopIds).getCheckedData();
        Map<String, Object> spuInfo = spuApi.getSkuCountByShopIds(shopIds).getCheckedData();
        log.info("getSimpleDetailPage: {} , {}",mpPage.getRecords().get(0), orderInfo.get(mpPage.getRecords().get(0).getId().toString()));
        mpPage.getRecords().forEach(
                shop -> shop.setOrderCount((Integer) orderInfo.get(String.valueOf(shop.getId())))
                        .setSpuCount((Integer) spuInfo.get(String.valueOf(shop.getId())))
        );

        return new PageResult<>(mpPage.getRecords(), mpPage.getTotal(), totalPage);
    }

    @Override
    public List<ShopDetailDO> getDetailList(ShopDetailExportReqVO exportReqVO) {
        return baseMapper.selectList(exportReqVO);
    }

}
